using System;
using System.Globalization;


namespace Waymex.Gps.Nmea
{
	/// <summary>
	/// GSA NMEA sentence class.
	/// </summary>
	public class SentenceGsa : Sentence
	{
		private const string C_SENTENCE_TYPE = "GSA";

		private GsaMode m_utMode;
		private GsaFixType m_utFixType; 
		private GsaSatelliteCollection m_colSatellites = new GsaSatelliteCollection(); 
		private double m_dblPositionDilution = 0.0; 
		private double m_dblHorizontalDilution = 0.0;
		private double m_dblVerticalDilution = 0.0;

		/// <summary>
		/// Enumeration used to describe the GSA mode.
		/// </summary>
		public enum GsaMode
		{
			/// <summary>
			/// Unknown.
			/// </summary>
			ModeUnknown = 0,
			/// <summary>
			/// Automatic.
			/// </summary>
			ModeAutomatic = 1,
			/// <summary>
			/// Manual.
			/// </summary>
			ModeManual = 2
		}
		
		/// <summary>
		/// Enumeration used to describe the GSA fix type.
		/// </summary>
		public enum GsaFixType
		{
			/// <summary>
			/// Unknown
			/// </summary>
			FixTypeUnknown = 0,
			/// <summary>
			/// Not Available
			/// </summary>
			FixTypeNotAvailable = 1,
			/// <summary>
			/// 2D fix.
			/// </summary>
			FixType2D = 2,
			/// <summary>
			/// 3D fix.
			/// </summary>
			FixType3D = 3
		}
		/// <summary>
		/// Constructor for the SentenceGsa class.
		/// </summary>
        public SentenceGsa(string sentence)
            : base(sentence)
		{
			try
			{
				//check the type to ensure that we can continue
				if(this.TypeId.ToUpper(CultureInfo.InvariantCulture) == C_SENTENCE_TYPE)
				{
                    Populate(sentence);
				}
				else
				{
					throw new InvalidSentence(C_MSG_001);
				}
			}
			catch(Exception e)
			{
                throw new InvalidSentence(e.Message, e);
			}
		}
		private void Populate(string p_strSentence)
		{
			int intIndex = 0;
			if(SentenceItemExists(1)) 
			{
				switch(m_astrSentence[1].ToUpper(CultureInfo.InvariantCulture))
				{
					case "A":
						m_utMode = GsaMode.ModeAutomatic;
						break;
					case "M":
						m_utMode = GsaMode.ModeManual;
						break;
					default:
						m_utMode = GsaMode.ModeUnknown;
						break;
				}
			}
			else
			{
				m_utMode = GsaMode.ModeUnknown;

			}
			if(SentenceItemExists(2)) 
			{
				switch(m_astrSentence[2].ToUpper(CultureInfo.InvariantCulture))
				{
					case "1":
						m_utFixType = GsaFixType.FixTypeNotAvailable;
						break;
					case "2":
						m_utFixType = GsaFixType.FixType2D;
						break;
					case "3":
						m_utFixType = GsaFixType.FixType3D;
						break;
					default:
						m_utFixType = GsaFixType.FixTypeUnknown;
						break;
				}
			}
			else
			{
				m_utFixType = GsaFixType.FixTypeUnknown;

			}
			
			intIndex = m_astrSentence.Length - 3;

			for(int f = 3; f < intIndex; f++) //maximum of 12 satellites
			{
				//dont add an object to the collection if the Satellite PRN Number is not valid
				if(IsNumeric(m_astrSentence[f]))
				{
					GsaSatellite objSatellite = new GsaSatellite();
                    objSatellite.SatellitePrn = Convert.ToInt32(m_astrSentence[f], CultureInfo.InvariantCulture);
					m_colSatellites.Add(objSatellite);
					objSatellite = null;
				}			
			}
			//work out where the next element is
			intIndex = m_astrSentence.Length;
			m_dblPositionDilution = FormatNumber(m_astrSentence[intIndex - 3]);
			m_dblHorizontalDilution = FormatNumber(m_astrSentence[intIndex - 2]);
			m_dblVerticalDilution = FormatNumber(m_astrSentence[intIndex - 1]);
		}

		///<summary>
		///Returns the Selection Mode.
		///</summary>
		public GsaMode Mode
		{
			get
			{
				return m_utMode;
			}
			set
			{
				m_utMode = value;
			}
		}

		///<summary>
		///Returns the Satellite Fix Type.
		///</summary>
		public GsaFixType FixType
		{
			get
			{
				return m_utFixType;
			}
			set
			{
				m_utFixType = value;
			}
		}

		///<summary>
		///Returns a GsaSatelliteCollection collection of GsaSatellite objects, each GsaSatellite
		///object represents a satellite used in the solution.
		///</summary>
		public GsaSatelliteCollection Satellites
		{
			get
			{
				return m_colSatellites;
			}
			set
			{
				m_colSatellites = value;
			}
		}

		///<summary>
		///Returns the Position Dilution of Precision.
		///</summary>
		public double PositionDilution
		{
			get
			{
				return m_dblPositionDilution;
			}
			set
			{
				m_dblPositionDilution = value;
			}
		}

		///<summary>
		///Returns the Horizontal Dilution of Precision.
		///</summary>
		public double HorizontalDilution
		{
			get
			{
				return m_dblHorizontalDilution;
			}
			set
			{
				m_dblHorizontalDilution = value;
			}
		}
		///<summary>
		///Returns the Vertical Dilution of Precision.
		///</summary>
		public double VerticalDilution
		{
			get
			{
				return m_dblVerticalDilution;
			}
			set
			{
				m_dblVerticalDilution = value;
			}
		}
	}
}
